/*
 * Copyright (c)  2020,  DataPipeline
 * All rights reserved.
 *
 * Id:ClassAnnotation.java   2020-07-18 16:04 wanglijun
 */
package cn.datacare.orm.database;

import cn.datacare.orm.annotation.*;
import cn.datacare.orm.annotation.builder.AttributeBuilderHolder;
import cn.datacare.orm.annotation.builder.ObjectBuilderHolder;
import cn.datacare.orm.annotation.builder.ObjectPersistBuilder;
import cn.datacare.orm.annotation.builder.ObjectSelectBuilder;
import cn.datacare.orm.concurrent.CaseInsensitiveHashMap;
import cn.datacare.orm.exception.OrmCoreException;
import cn.datacare.orm.exception.OrmErrorCode;
import cn.datacare.orm.util.BeanUtils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 * Title: 注解解析
 * </p>
 * <p>
 * Description: 注解解析
 * </p>
 * <p>
 * Copyright: Copyright (c) 2020
 * </p>
 * <p>
 * Company/Department: DataPipeline
 * </p>
 *
 * @author wanglijun
 * @version 1.0
 * @since 2020-07-18 16:04
 */
public class ClassAnnotation {
    static Map<Class, ClassAnnotation> cache = new ConcurrentHashMap<>();
    Class entity = null;
    //update和insert 忽略策略
    Map<String, ClassDesc.ColumnIgnoreStatus> attrIgnores = new HashMap<>();
    // 逻辑删除标记
    String logicDeleteAttrName = null;

    int logicDeleteAttrValue = 0;

    //版本号标记
    String versionProperty;

    int initVersionValue = -1;

    //属性对应的处理类,TODO优化，设置为null，否则jdk6有一定损耗
    CaseInsensitiveHashMap<String, AttributeBuilderHolder> colHandlers = new CaseInsensitiveHashMap<>();
    //类对应的处理类，可以多个
    List<ObjectBuilderHolder> objectBuilders = new ArrayList<>();

    protected ClassAnnotation(Class entity) {
        this.entity = entity;

    }

    public static ClassAnnotation getClassAnnotation(Class entity) {
        ClassAnnotation ca = cache.get(entity);
        if (ca != null) {
            return ca;
        }
        ca = new ClassAnnotation(entity);
        ca.init();
        cache.put(entity, ca);
        return ca;
    }

    protected void init() {
        typeCheck();
        propertyCheck();

    }

    protected void typeCheck() {
        Annotation[] ans = this.entity.getAnnotations();
        List<ObjectBuilderHolder> list = new ArrayList<>();
        for (Annotation an : ans) {
            Builder builder = an.annotationType().getAnnotation(Builder.class);
            if (builder == null) {
                continue;
            }
            Class clz = builder.value();
            Object obj = BeanUtils.newInstance(clz);
            if (!(obj instanceof ObjectPersistBuilder || obj instanceof ObjectSelectBuilder)) {
                throw new OrmCoreException(OrmErrorCode.ANNOTATION_DEFINE_ERROR, entity, an);
            }
            ObjectBuilderHolder holder = new ObjectBuilderHolder(an, builder);
            list.add(holder);

        }
        objectBuilders.addAll(list);
    }

    protected void propertyCheck() {
        PropertyDescriptor[] ps = this.getPropertyDescriptor();
        for (PropertyDescriptor p : ps) {
            Method readMethod = p.getReadMethod();
            //各种内置注解
            ColumnIgnore sqlIgnore = BeanUtils.getAnnotation(entity, p.getName(), readMethod, ColumnIgnore.class);
            if (sqlIgnore != null) {
                attrIgnores.put(p.getName(), new ClassDesc.ColumnIgnoreStatus(sqlIgnore));
            } else {

                InsertIgnore ig = BeanUtils.getAnnotation(entity, p.getName(), readMethod, InsertIgnore.class);
                UpdateIgnore ug = BeanUtils.getAnnotation(entity, p.getName(), readMethod, UpdateIgnore.class);
                if (ig != null || ug != null) {
                    attrIgnores.put(p.getName(), new ClassDesc.ColumnIgnoreStatus(ig, ug));
                }
            }

            LogicDelete logicDelete = BeanUtils.getAnnotation(entity, p.getName(), readMethod, LogicDelete.class);
            if (logicDelete != null) {
                this.logicDeleteAttrName = p.getName();
                this.logicDeleteAttrValue = logicDelete.value();
            }


            Version version = BeanUtils.getAnnotation(entity, p.getName(), readMethod, Version.class);
            if (version != null) {
                this.versionProperty = p.getName();
                this.initVersionValue = version.value();
            }

            AttributeBuilderHolder holder = BeanUtils.getAttributeHandlerHolder(entity, p.getName(), p);
            if (holder != null) {
                //判断是否有对字段特殊处理
                colHandlers.put(p.getName(), holder);
            }


        }
    }

    public PropertyDescriptor[] getPropertyDescriptor() {
        try {
            return BeanUtils.propertyDescriptors(entity);
        } catch (IntrospectionException e) {
            throw new RuntimeException(e);
        }
    }

    public InsertIgnore getInsertIgnore(String property) {
        return null;
    }

    public CaseInsensitiveHashMap<String, AttributeBuilderHolder> getColHandlers() {
        return colHandlers;
    }

    public Class getEntity() {
        return entity;
    }

    public Map<String, ClassDesc.ColumnIgnoreStatus> getAttrIgnores() {
        return attrIgnores;
    }

    public String getLogicDeleteAttrName() {
        return logicDeleteAttrName;
    }

    public int getLogicDeleteAttrValue() {
        return logicDeleteAttrValue;
    }

    public String getVersionProperty() {
        return versionProperty;
    }

    public List<ObjectBuilderHolder> getObjectBuilders() {
        return objectBuilders;
    }

    public void setObjectBuilders(List<ObjectBuilderHolder> objectBuilders) {
        this.objectBuilders = objectBuilders;
    }
}
